Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

fix($sniffer): fix history sniffing in Chrome Packaged Apps #13945

Conversation

gkalpak
Copy link
Member

@gkalpak gkalpak commented Feb 4, 2016

Although window.history is present in the context of Chrome Packaged Apps, it is not allowed to
access window.history.pushState or window.history.state, resulting in errors when trying to
"sniff" history support.
This commit fixes it by detecting a Chrome Packaged App (through the presence of
window.chrome.app.runtime). Note that window.chrome.app is present in the context of "normal"
webpages as well, but it doesn't have the runtime property, which is only available to packaged
apps (e.g. see https://developer.chrome.com/apps/api_index).

Fixes #11932

The first commit is just some cleanup (that makes the diff look worse than it actually is).
Included it separately, so the fix is easier to review - could be squashed upon merging.

Although `window.history` is present in the context of Chrome Packaged Apps, it is not allowed to
access `window.history.pushState` or `window.history.state`, resulting in errors when trying to
"sniff" history support.
This commit fixes it by detecting a Chrome Packaged App (through the presence of
`window.chrome.app.runtime`). Note that `window.chrome.app` is present in the context of "normal"
webpages as well, but it doesn't have the `runtime` property, which is only available to packaged
apps (e.g. see https://developer.chrome.com/apps/api_index).

Fixes angular#11932
@@ -17,6 +17,8 @@
function $SnifferProvider() {
this.$get = ['$window', '$document', function($window, $document) {
var eventSupport = {},
isChromePackagedApp = $window.chrome && $window.chrome.app && $window.chrome.app.runtime,
hasHistoryPushState = $window.history && $window.history.pushState,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just an idea, but could we use 'pushstate' in $window.history?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we can. But what is the benefit ? We want to return false in Chrome Packaged Apps (and 'pushState' in window.history returns true, although we are not allowed to access history.pushState or histroy.state).

(BTW, this fix is not correct, I need to update it.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, okay, I see

@gkalpak gkalpak force-pushed the fix-sniffer-history-for-chrome-packaged-apps branch from 6d84ed5 to 6cab4ad Compare February 4, 2016 13:36
@gkalpak
Copy link
Member Author

gkalpak commented Feb 4, 2016

I pushed a 3rd commit that prevents logging exceptions in the console. PTAL

@@ -61,7 +65,7 @@ function $SnifferProvider() {
// so let's not use the history API also
// We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
// jshint -W018
history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee),
history: !!(hasHistoryPushState && !(android < 4) && !boxee),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why move the $window.history.... checks out of this expression? Is Chrome more special that android < 4 or boxee?

I would expect it is clearer to simply change this to:

!!(!isChromePackagedApp && $window.history && $window.history.pushState && !(android < 4) && !boxee),

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is Chrome more special that android < 4 or boxee

Yeah, Chrome is actually very close to my heart 😛

I put it this way for readability (avoiding !!(! and hitting the 100 chars per line limit, thus having to wrap).
I'm fine having it either way.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Plus, if I have isChromePackagedApp and hasHistoryPushState close together, it's easier for reference wrt to the comment explaining why Chrome Packaged Apps need special handling when checking for the existence of history.pushState.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, how about:

// Chrome Packaged Apps are not allowed to access `history.pushState`. They can be detected by
// the presence of `chrome.app.runtime` (see https://developer.chrome.com/apps/api_index)
isChromePackagedApp = $window.chrome && $window.chrome.app && $window.chrome.app.runtime,
hasHistoryPushState = $window.history && $window.history.pushState,

then later:

history: !isChromePackagedApp && !!hasHistoryPushState && !(android < 4) && !boxee,

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The thing is that we shouldn't even try to touch history.pushState in packaged apps (or there'll be errors).
That's why we need the !isChromePackagedApp short-circuiting at the beginning of hasHistoryPushState.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh :-(

@petebacondarwin
Copy link
Member

A few minor comments but generally looks good to me.

@petebacondarwin
Copy link
Member

LGTM - squash and merge

@gkalpak gkalpak closed this in 9f5526f Mar 22, 2016
gkalpak added a commit that referenced this pull request Mar 22, 2016
Although `window.history` is present in the context of Chrome Packaged Apps, it is not allowed to
access `window.history.pushState` or `window.history.state`, resulting in errors when trying to
"sniff" history support.
This commit fixes it by detecting a Chrome Packaged App (through the presence of
`window.chrome.app.runtime`). Note that `window.chrome.app` is present in the context of "normal"
webpages as well, but it doesn't have the `runtime` property, which is only available to packaged
apps (e.g. see https://developer.chrome.com/apps/api_index).

(It also also contains some style changes for making the structure and layout of `$sniffer` tests
 more consistent.)

Fixes #11932

Closes #13945
@gkalpak gkalpak deleted the fix-sniffer-history-for-chrome-packaged-apps branch March 27, 2016 17:49
Parent5446 added a commit to Parent5446/angular.js that referenced this pull request Aug 12, 2016
Check in $sniffer if operating in a sandboxed Chrome app, which does not
have access to chrome.app.runtime like other apps, but also does not
have access to history.pushState. If inside a sandboxed Chrome app, do
not try and use history.pushState, else an error will occur. See angular#11932
and angular#13945 for previous work.
gkalpak pushed a commit that referenced this pull request Sep 8, 2016
…aged Apps

While sandboxed Chrome Packaged Apps (CPAs) have the same restrictions wrt
accessing `history.pushState` as "normal" CPAs, they can't be detected in the
same way, as they do not have access to the same APIs.
Previously, due to their differences from normal CPAs, `$sniffer` would fail to
detect sandboxed CPAs and incorrectly assume `history.pushState` is available
(which resulted in an error being thrown).
This commit fixes the detection of sandboxed CPAs in `$sniffer`.

See #11932 and #13945 for previous work.

Closes #15021
gkalpak pushed a commit that referenced this pull request Sep 8, 2016
…aged Apps

While sandboxed Chrome Packaged Apps (CPAs) have the same restrictions wrt
accessing `history.pushState` as "normal" CPAs, they can't be detected in the
same way, as they do not have access to the same APIs.
Previously, due to their differences from normal CPAs, `$sniffer` would fail to
detect sandboxed CPAs and incorrectly assume `history.pushState` is available
(which resulted in an error being thrown).
This commit fixes the detection of sandboxed CPAs in `$sniffer`.

See #11932 and #13945 for previous work.

Closes #15021
petebacondarwin pushed a commit to petebacondarwin/angular.js that referenced this pull request Nov 21, 2016
…aged Apps

While sandboxed Chrome Packaged Apps (CPAs) have the same restrictions wrt
accessing `history.pushState` as "normal" CPAs, they can't be detected in the
same way, as they do not have access to the same APIs.
Previously, due to their differences from normal CPAs, `$sniffer` would fail to
detect sandboxed CPAs and incorrectly assume `history.pushState` is available
(which resulted in an error being thrown).
This commit fixes the detection of sandboxed CPAs in `$sniffer`.

See angular#11932 and angular#13945 for previous work.

Closes angular#15021
petebacondarwin pushed a commit to petebacondarwin/angular.js that referenced this pull request Nov 21, 2016
…aged Apps

While sandboxed Chrome Packaged Apps (CPAs) have the same restrictions wrt
accessing `history.pushState` as "normal" CPAs, they can't be detected in the
same way, as they do not have access to the same APIs.
Previously, due to their differences from normal CPAs, `$sniffer` would fail to
detect sandboxed CPAs and incorrectly assume `history.pushState` is available
(which resulted in an error being thrown).
This commit fixes the detection of sandboxed CPAs in `$sniffer`.

See angular#11932 and angular#13945 for previous work.

Closes angular#15021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

history.pushState is not available in packaged apps.
4 participants